//! SQL Virtual Machine (VM) bytecode execution engine
//!
//! This module implements a bytecode-based SQL execution engine inspired by SQLite's architecture.
//! The engine operates in two phases:
//! 1. Compile SQL statements into bytecode instructions
//! 2. Execute bytecode instructions in a virtual machine (VM)
//!
//! For more information on this approach, see: https://www.sqlite.org/opcode.html

pub mod bytecode;
pub mod compiler;
pub mod engine;

#[cfg(test)]
mod tests;

use crate::database::Database;
use crate::error::SqawkResult;
use crate::table::Table;

/// Execute SQL using the VM execution engine
///
/// This is the main entry point for VM-based SQL execution in Sqawk.
/// It implements a two-phase approach:
/// 1. SQL parsing and bytecode generation
/// 2. VM execution of bytecode instructions
pub fn execute_vm(sql: &str, database: &Database, verbose: bool) -> SqawkResult<Option<Table>> {
    if verbose {
        println!("VM Engine: Executing SQL via bytecode: {}", sql);
    }

    // PHASE 1: SQL → BYTECODE COMPILATION

    // Use the SqlCompiler to convert the SQL statement to bytecode
    let mut compiler = compiler::SqlCompiler::new(database, verbose);
    let program = compiler.compile(sql)?;

    if verbose {
        println!("Phase 1 complete - Generated bytecode:");
        println!("{}", program);
    }

    // PHASE 2: BYTECODE → EXECUTION & RESULTS

    // Initialize the VM engine with the bytecode program
    let mut vm = engine::VmEngine::new(database, verbose);
    vm.init(program);

    if verbose {
        println!("Phase 2 starting - Executing bytecode in VM");
    }

    // Execute all instructions in the program
    vm.execute()?;

    if verbose {
        println!("Phase 2 complete - Execution finished");
    }

    // Build a table from the execution results
    let result_table = vm.create_result_table();

    if verbose && result_table.is_ok() {
        if let Some(table) = &result_table.as_ref().unwrap() {
            println!(
                "Result table created with {} rows and {} columns",
                table.row_count(),
                table.column_count()
            );
        } else {
            println!("Query executed successfully with no result table");
        }
    }

    // Return the resulting table (or None for statements with no results)
    result_table
}
